package com.carter.springframework.core.annotation;

import com.sun.istack.internal.Nullable;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * TypeMappedAnnotations是表示某一个可注解元素的注解的集合，可以通过其提供的方法获取注解或元注解
 */
final class TypeMappedAnnotations implements MergedAnnotations {
    static final MergedAnnotations NONE = new TypeMappedAnnotations(null, new Annotation[0], RepeatableContainers.none(), AnnotationFilter.ALL);

    @Nullable
    private final Object source;

    @Nullable
    private final AnnotatedElement element;

    @Nullable
    private final SearchStrategy searchStrategy;

    @Nullable
    private final Annotation[] annotations;

    private final RepeatableContainers repeatableContainers;

    private final AnnotationFilter annotationFilter;

    @Nullable
    private volatile List<Aggregate> aggregates;

    private TypeMappedAnnotations(AnnotatedElement element, SearchStrategy searchStrategy, RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
        this.source = element;
        this.element = element;
        this.searchStrategy = searchStrategy;
        this.annotations = null;
        this.repeatableContainers = repeatableContainers;
        this.annotationFilter = annotationFilter;
    }

    private TypeMappedAnnotations(@Nullable Object source, Annotation[] annotations, RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {

        this.source = source;
        this.element = null;
        this.searchStrategy = null;
        this.annotations = annotations;
        this.repeatableContainers = repeatableContainers;
        this.annotationFilter = annotationFilter;
    }

    static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy, RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
        // 该元素若符合下述任一情况，则直接返回空注解：
        // a.被处理的元素属于java包、被java包中的对象声明，或者就是Ordered.class
        // b.只查找元素直接声明的注解，但是元素本身没有声明任何注解
        // c.查找元素的层级结构，但是元素本身没有任何层级结构
        // d.元素是桥接方法
        if (AnnotationsScanner.isKnownEmpty(element, searchStrategy)) {
            return NONE;
        }
        //返回一个具体的实现类实例
        return new TypeMappedAnnotations(element, searchStrategy, repeatableContainers, annotationFilter);
    }

    @Override
    public <A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType) {
        return null;
    }

    @Override
    public <A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType, Predicate<? super MergedAnnotation<A>> predicate) {
        return null;
    }

    @Override
    public <A extends Annotation> MergedAnnotation<A> get(Class<A> annotationType, Predicate<? super MergedAnnotation<A>> predicate, MergedAnnotationSelector<A> selector) {
        //如果查找的注解类型直接通不过过滤器，就没必要继续搜索了
        if (this.annotationFilter.matches(annotationType)) {
            return MergedAnnotation.missing();
        }
        //使用AnnotationScanner对元素层级结构进行查找
        MergedAnnotation<A> result = scan(annotationType, new MergedAnnotationFinder<>(annotationType, predicate, selector));
        return result != null ? result : MergedAnnotation.missing();

    }

    private <C, R> R scan(C criteria, AnnotationsProcessor<C, R> processor) {
        if (this.annotations != null) {
            R result = processor.doWithAnnotations(criteria, 0, this.source, this.annotations);
            return processor.finish(result);
        }
        if (this.element != null && this.searchStrategy != null) {
            return AnnotationsScanner.scan(criteria, this.element, this.searchStrategy, processor);
        }
        return null;
    }

    private static boolean isMappingForType(AnnotationTypeMapping mapping, AnnotationFilter annotationFilter, Object requiredType) {
        Class<? extends Annotation> actualType = mapping.getAnnotationType();
        return (!annotationFilter.matches(actualType) && (requiredType == null || actualType == requiredType || actualType.getName().equals(requiredType)));
    }

    @Override
    public <A extends Annotation> MergedAnnotation<A> get(String annotationType) {
        return null;
    }

    @Override
    public <A extends Annotation> MergedAnnotation<A> get(String annotationType, Predicate<? super MergedAnnotation<A>> predicate) {
        return null;
    }

    @Override
    public <A extends Annotation> MergedAnnotation<A> get(String annotationType, Predicate<? super MergedAnnotation<A>> predicate, MergedAnnotationSelector<A> selector) {
        return null;
    }

    @Override
    public boolean isDirectlyPresent(String annotationType) {
        return false;
    }

    @Override
    public Iterator<MergedAnnotation<Annotation>> iterator() {
        return null;
    }

    /**
     * Aggregate是TypeMappedAnnotations 的内部类
     *
     *     接受一组注解数组 annotations；
     *     遍历注解数组，解析这些注解的元注解，并将其与解析得到的元注解转为 AnnotationTypeMappings；
     *     把 AnnotationTypeMappings放到对应的源注解在annotations中的下标的位置
     */
    private static class Aggregate {

        private final int aggregateIndex;

        @Nullable
        private final Object source;

        private final List<Annotation> annotations;

        private final AnnotationTypeMappings[] mappings;

        Aggregate(int aggregateIndex, @Nullable Object source, List<Annotation> annotations) {
            this.aggregateIndex = aggregateIndex;
            this.source = source;
            this.annotations = annotations;
            this.mappings = new AnnotationTypeMappings[annotations.size()];
            for (int i = 0; i < annotations.size(); i++) {
                this.mappings[i] = AnnotationTypeMappings.forAnnotationType(annotations.get(i).annotationType());
            }
        }

        int size() {
            return this.annotations.size();
        }

        @Nullable
        AnnotationTypeMapping getMapping(int annotationIndex, int mappingIndex) {
            AnnotationTypeMappings mappings = getMappings(annotationIndex);
            return (mappingIndex < mappings.size() ? mappings.get(mappingIndex) : null);
        }

        AnnotationTypeMappings getMappings(int annotationIndex) {
            return this.mappings[annotationIndex];
        }


        @Nullable
        <A extends Annotation> MergedAnnotation<A> createMergedAnnotationIfPossible(int annotationIndex, int mappingIndex) {
            return TypeMappedAnnotation.createIfPossible(
                    this.mappings[annotationIndex].get(mappingIndex), this.source,
                    this.annotations.get(annotationIndex), this.aggregateIndex);
        }
    }

    /**
     * 用于从AnnotationScanner扫描的注解中，找到一个指定类型的注解/合并注解
     * @param <A>
     */
    private class MergedAnnotationFinder<A extends Annotation> implements AnnotationsProcessor<Object, MergedAnnotation<A>> {
        private final Object requiredType;

        @Nullable
        private final Predicate<? super MergedAnnotation<A>> predicate;

        //合并注解选择器
        private final MergedAnnotationSelector<A> selector;

        @Nullable
        private MergedAnnotation<A> result;

        MergedAnnotationFinder(Object requiredType, @Nullable Predicate<? super MergedAnnotation<A>> predicate,
                               @Nullable MergedAnnotationSelector<A> selector) {

            this.requiredType = requiredType;
            this.predicate = predicate;
            this.selector = (selector != null ? selector : MergedAnnotationSelectors.nearest());
        }

        @Override
        public MergedAnnotation<A> doWithAggregate(Object context, int aggregateIndex) {
            return this.result;
        }

        @Override
        public MergedAnnotation<A> doWithAnnotations(Object type, int aggregateIndex, Object source, Annotation[] annotations) {
            for (Annotation annotation : annotations) {
                if (annotation != null && !annotationFilter.matches(annotation)) {
                    MergedAnnotation<A> result = process(type, aggregateIndex, source, annotation);
                    if (result != null) {
                        return result;
                    }
                }
            }
            return null;
        }

        /**
         * 一个普通的注解的元注解被解析为AnnotationTypeMappings与AnnotationTypeMapping
         *
         * @param type
         * @param aggregateIndex
         * @param source
         * @param annotation
         * @return
         */
        private MergedAnnotation<A> process(Object type, int aggregateIndex, Object source, Annotation annotation) {
            //若注解是可重复注解的容器注解则平摊
            Annotation[] repeatedAnnotations = repeatableContainers.findRepeatedAnnotations(annotation);
            if (repeatedAnnotations != null) {
                return doWithAnnotations(type, aggregateIndex, source, repeatedAnnotations);
            }
            //获取这个注解的元注解，并将自己及这些元注解都转为AnnotationTypeMappings
            AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(annotation.annotationType(), repeatableContainers, annotationFilter);
            for (int i = 0; i < mappings.size(); i++) {
                //遍历这些注解，如果有注解符合条件，则将其转为合并注解
                AnnotationTypeMapping mapping = mappings.get(i);
                if (isMappingForType(mapping, annotationFilter, this.requiredType)) {
                    //todo:根据符合条件的类型映射对象，创建聚合注解
                    MergedAnnotation<A> candidate = TypeMappedAnnotation.createIfPossible(mapping, source, annotation, aggregateIndex);
                    //如果当前已经存在符合条件的合并注解了，则使用选择器判断两个注解到底谁会更合适，然后将其更新到成员变量result中
                    if (candidate != null && (this.predicate == null || this.predicate.test(candidate))) {
                        //判断该注解是否是最符合的结果，如果是就没必要再比较了，直接返回
                        if (this.selector.isBestCandidate(candidate)) {
                            return candidate;
                        }
                        updateLastResult(candidate);
                    }
                }
            }
            return null;
        }

        private void updateLastResult(MergedAnnotation<A> candidate) {
            MergedAnnotation<A> lastResult = this.result;
            this.result = (lastResult != null ? this.selector.select(lastResult, candidate) : candidate);
        }
    }

    /**
     * 判断注解是否直接或间接（即不存在可重复注解，但是存在可重复注解的容器注解这种情况）存在
     */
    private static final class IsPresent implements AnnotationsProcessor<Object, Boolean> {

        private static final IsPresent[] SHARED;
        static {
            SHARED = new IsPresent[4];
            SHARED[0] = new IsPresent(RepeatableContainers.none(), AnnotationFilter.PLAIN, true);
            SHARED[1] = new IsPresent(RepeatableContainers.none(), AnnotationFilter.PLAIN, false);
            SHARED[2] = new IsPresent(RepeatableContainers.standardRepeatables(), AnnotationFilter.PLAIN, true);
            SHARED[3] = new IsPresent(RepeatableContainers.standardRepeatables(), AnnotationFilter.PLAIN, false);
        }

        private final RepeatableContainers repeatableContainers;

        private final AnnotationFilter annotationFilter;

        private final boolean directOnly;

        private IsPresent(RepeatableContainers repeatableContainers,
                          AnnotationFilter annotationFilter, boolean directOnly) {

            this.repeatableContainers = repeatableContainers;
            this.annotationFilter = annotationFilter;
            this.directOnly = directOnly;
        }

        /**
         * 这个方法依次进行三次判断：
         *
         *     当前注解是否就是要找的注解？
         *     当前注解如果是个可从重复注解的容器注解，则将其内部的可重复注解全部取出平摊后，是否存在要找的注解？
         *     如果当不限制只查找注解本身，则继续搜索它的所有元注解，这些元注解是否存在要找的注解？
         *
         * 只要这三个条件任意一个满足，则就会认为该注解在AnnotationScanner的扫描范围内存在
         *
         * @param requiredType
         * @param aggregateIndex
         * @param source
         * @param annotations
         * @return
         */
        @Override
        @Nullable
        public Boolean doWithAnnotations(Object requiredType, int aggregateIndex, @Nullable Object source, Annotation[] annotations) {
            for (Annotation annotation : annotations) {
                if (annotation != null) {
                    Class<? extends Annotation> type = annotation.annotationType();
                    //若注解类型不为空，且能通过过滤器校验，则开始判断过程
                    if (type != null && !this.annotationFilter.matches(type)) {
                        //1.该注解类型就是要查找的类型
                        if (type == requiredType || type.getName().equals(requiredType)) {
                            return Boolean.TRUE;
                        }
                        //2.该注解不是要查找的类型，但是它是一个容器注解，则将其全部平摊
                        Annotation[] repeatedAnnotations = this.repeatableContainers.findRepeatedAnnotations(annotation);
                        if (repeatedAnnotations != null) {
                            //递归判断平摊后的注解是否符合条件
                            Boolean result = doWithAnnotations(requiredType, aggregateIndex, source, repeatedAnnotations);
                            if (result != null) {
                                return result;
                            }
                        }
                        //3.如果上述两者情况都不满足，则且并不限制值仅查找直接存在的注解
                        //则查找这个注解的元注解，判断其所有元注解是否存在该指定注解
                        if (!this.directOnly) {
                            AnnotationTypeMappings mappings = AnnotationTypeMappings.forAnnotationType(type);
                            for (int i = 0; i < mappings.size(); i++) {
                                AnnotationTypeMapping mapping = mappings.get(i);
                                if (isMappingForType(mapping, this.annotationFilter, requiredType)) {
                                    return Boolean.TRUE;
                                }
                            }
                        }
                    }
                }
            }
            return null;
        }

        static IsPresent get(RepeatableContainers repeatableContainers,
                             AnnotationFilter annotationFilter, boolean directOnly) {

            // Use a single shared instance for common combinations
            if (annotationFilter == AnnotationFilter.PLAIN) {
                if (repeatableContainers == RepeatableContainers.none()) {
                    return SHARED[directOnly ? 0 : 1];
                }
                if (repeatableContainers == RepeatableContainers.standardRepeatables()) {
                    return SHARED[directOnly ? 2 : 3];
                }
            }
            return new IsPresent(repeatableContainers, annotationFilter, directOnly);
        }
    }

    /**
     * 用于收集全部扫描到的注解
     */
    private class AggregatesCollector implements AnnotationsProcessor<Object, List<Aggregate>> {

        private final List<Aggregate> aggregates = new ArrayList<>();

        @Override
        @Nullable
        public List<Aggregate> doWithAnnotations(Object criteria, int aggregateIndex,
                                                 @Nullable Object source, Annotation[] annotations) {

            //创建一个Aggregate
            this.aggregates.add(createAggregate(aggregateIndex, source, annotations));
            return null;
        }

        private Aggregate createAggregate(int aggregateIndex, @Nullable Object source, Annotation[] annotations) {
            List<Annotation> aggregateAnnotations = getAggregateAnnotations(annotations);
            return new Aggregate(aggregateIndex, source, aggregateAnnotations);
        }

        private List<Annotation> getAggregateAnnotations(Annotation[] annotations) {
            List<Annotation> result = new ArrayList<>(annotations.length);
            addAggregateAnnotations(result, annotations);
            return result;
        }

        private void addAggregateAnnotations(List<Annotation> aggregateAnnotations, Annotation[] annotations) {
            for (Annotation annotation : annotations) {
                if (annotation != null && !annotationFilter.matches(annotation)) {
                    //若是容器注解就全部摊平
                    Annotation[] repeatedAnnotations = repeatableContainers.findRepeatedAnnotations(annotation);
                    if (repeatedAnnotations != null) {
                        addAggregateAnnotations(aggregateAnnotations, repeatedAnnotations);
                    }
                    else {
                        //收集该注解
                        aggregateAnnotations.add(annotation);
                    }
                }
            }
        }

        @Override
        public List<Aggregate> finish(@Nullable List<Aggregate> processResult) {
            return this.aggregates;
        }
    }

    private class AggregatesSpliterator<A extends Annotation> implements Spliterator<MergedAnnotation<A>> {

        @Nullable
        private final Object requiredType;

        private final List<Aggregate> aggregates;

        private int aggregateCursor;

        @Nullable
        private int[] mappingCursors;

        AggregatesSpliterator(@Nullable Object requiredType, List<Aggregate> aggregates) {
            this.requiredType = requiredType;
            this.aggregates = aggregates;
            this.aggregateCursor = 0;
        }

        @Override
        public boolean tryAdvance(Consumer<? super MergedAnnotation<A>> action) {
            while (this.aggregateCursor < this.aggregates.size()) {
                Aggregate aggregate = this.aggregates.get(this.aggregateCursor);
                if (tryAdvance(aggregate, action)) {
                    return true;
                }
                this.aggregateCursor++;
                this.mappingCursors = null;
            }
            return false;
        }

        private boolean tryAdvance(Aggregate aggregate, Consumer<? super MergedAnnotation<A>> action) {
            if (this.mappingCursors == null) {
                this.mappingCursors = new int[aggregate.size()];
            }
            int lowestDistance = Integer.MAX_VALUE;
            int annotationResult = -1;
            for (int annotationIndex = 0; annotationIndex < aggregate.size(); annotationIndex++) {
                AnnotationTypeMapping mapping = getNextSuitableMapping(aggregate, annotationIndex);
                if (mapping != null && mapping.getDistance() < lowestDistance) {
                    annotationResult = annotationIndex;
                    lowestDistance = mapping.getDistance();
                }
                if (lowestDistance == 0) {
                    break;
                }
            }
            if (annotationResult != -1) {
                MergedAnnotation<A> mergedAnnotation = aggregate.createMergedAnnotationIfPossible(
                        annotationResult, this.mappingCursors[annotationResult]);
                this.mappingCursors[annotationResult]++;
                if (mergedAnnotation == null) {
                    return tryAdvance(aggregate, action);
                }
                action.accept(mergedAnnotation);
                return true;
            }
            return false;
        }

        @Nullable
        private AnnotationTypeMapping getNextSuitableMapping(Aggregate aggregate, int annotationIndex) {
            int[] cursors = this.mappingCursors;
            if (cursors != null) {
                AnnotationTypeMapping mapping;
                do {
                    mapping = aggregate.getMapping(annotationIndex, cursors[annotationIndex]);
                    if (mapping != null && isMappingForType(mapping, annotationFilter, this.requiredType)) {
                        return mapping;
                    }
                    cursors[annotationIndex]++;
                }
                while (mapping != null);
            }
            return null;
        }

        @Override
        @Nullable
        public Spliterator<MergedAnnotation<A>> trySplit() {
            return null;
        }

        @Override
        public long estimateSize() {
            int size = 0;
            for (int aggregateIndex = this.aggregateCursor;
                 aggregateIndex < this.aggregates.size(); aggregateIndex++) {
                Aggregate aggregate = this.aggregates.get(aggregateIndex);
                for (int annotationIndex = 0; annotationIndex < aggregate.size(); annotationIndex++) {
                    AnnotationTypeMappings mappings = aggregate.getMappings(annotationIndex);
                    int numberOfMappings = mappings.size();
                    if (aggregateIndex == this.aggregateCursor && this.mappingCursors != null) {
                        numberOfMappings -= Math.min(this.mappingCursors[annotationIndex], mappings.size());
                    }
                    size += numberOfMappings;
                }
            }
            return size;
        }

        @Override
        public int characteristics() {
            return NONNULL | IMMUTABLE;
        }
    }

}
